package Algoritmo;

import Grafica.Vertice;
import java.util.LinkedList;
import InterfazPantera.PanteraView;

/**
     *
 * @author robertoanzaldua
 */
public abstract class AlgoritmoDistancia  extends Algoritmo{

    //La distancia y los predecesores
    protected int[]d;
    protected Vertice[]p;

    //El conjunto de vértices agregados a la cola
    protected LinkedList<Vertice> C;

    
    protected Vertice u;
    protected Vertice v;
    protected double b;
    protected int nV;
    protected int add;

    public AlgoritmoDistancia(PanteraView interfaz, String nombre){
        super(interfaz,nombre);
        d = new int[G.numV];
        p = new Vertice[G.numV];
    }

    protected abstract int dist();

    protected abstract int mueve(int i);

    protected abstract void mA();

    protected String imprimeC(){
        StringBuilder c = new StringBuilder("C = <");
        for(Vertice V : C)
            c.append(V.ID()+",");

        c.deleteCharAt(c.length()-1);
        c.append(">;\n");
        return c.toString();
    }

        protected String[] p(){
        String[]pS = new String[G.numV];
        for(int i=0;i<G.numV;i++)
            pS[i] = p[i]!=null ? p[i].ID() : "N";
        return pS;
    }

    protected abstract Vertice asignaU();

    protected abstract void asignaV();

    protected void adicionales(){
        clics1--;
    }

    protected void inicializa(){
        agregaADesarrollo("---------------Inicialización--------------\n");
        for(int i=0;i<G.numV;i++){
            agregaADesarrollo(G.getV(i).ID()+".π ← nulo ; "+G.getV(i).ID()+".d ← ∞ \n");
            d[i] = Integer.MAX_VALUE;
        }
        dibuja(d,p());
        agregaADesarrollo("\n");
        clics++;
    }


    protected void inicializa1(){
        cambiaPaso(0,1);
        vertAleat = 2;// numA(G.numV);
        agregaADesarrollo("s = "+G.getV(vertAleat).ID()+";\n");
        G.marcaVerticePerm(vertAleat,"0.5,0.8,1");
        d[vertAleat] = 0;
        p[vertAleat] = null;
        dibuja(d,p());
        agregaADesarrollo(G.getV(vertAleat).ID()+".d ← 0 ; "+G.getV(vertAleat).ID()+".π ← nulo \n");
        clics++;
    }

    protected void inicializa2(){
        cambiaPaso(1,2);
        C = new LinkedList();
        C.add(G.getV(vertAleat));
        agregaADesarrollo(imprimeC());
        agregaADesarrollo("------------Fin de Inicialización------------\n");
        clics++;
    }

     protected void cicloC0(){
        cambiaPaso(nulo(2) ? 12+add : 2, !C.isEmpty() ? 3 : 13+add);
        if(!C.isEmpty()){
            enviaMensaje("C contiene a "+C.getFirst().ID());
            agregaADesarrollo("C contiene a "+C.getFirst().ID()+"\n");
            return;
        }
        enviaMensaje("C está vacío");
        clics = 4;
    }

    protected void cicloC1(){
        cambiaPaso(3,4);
        u = asignaU();
        agregaADesarrollo("u = "+u.ID()+"\n");
    }

    protected void cicloVAdy0(){
        cambiaPaso(4,5);
        if(u.disp()!=null){
            agregaADesarrollo("Los vértices adyacentes a "+u.ID()+" son:\n");
            for(Vertice V : u.ady())
                agregaADesarrollo(V.ID()+"\n");
            agregaADesarrollo("\n");            
            return;
        }

        agregaADesarrollo("u no tiene vértices adyacentes.\n\n");
        clics0 = 3;
        clics1 = -1;
    }

    protected void cicloVAdy1(){
        //if(u.ady().size()>0){
        if(u.adyC().size()>0){
            cambiaPaso(nulo(13) ? nulo(11) ?  nulo(5) ? nulo(10) ? 7 : 10 : 5 : 11 :13 , 6);
            asignaV();
        }else{
            cambiaPaso(nulo(13) ? nulo(11) ? nulo(5) ? nulo(7) ? 10 : 7 : 5 : 11 : 13,11+add);
            agregaADesarrollo(u.ID()+" ya no tiene mas vecinos.\n\n");
            clics0++;
            clics1 = -1;
        }
    }

    protected void cicloVAdy2(){
        cambiaPaso(nulo(6) ? 10 : 6,7);
        if(d[v.nV()]==Integer.MAX_VALUE)
            agregaADesarrollo(v.ID()+".d = ∞, es la primera ves que pasamos\n\n");
        else{
            agregaADesarrollo(v.ID()+".d != ∞\n\n");
            clics1 = mueve(1);
        }
    }

    protected void cicloVAdy3(){
        cambiaPaso(nulo(7) ? 11 : 7, nulo(7) ? 12 : 8);
        int du = d[u.nV()]+dist();
        d[v.nV()] = du;
        b = 1.0/du;
        mA();
        dibuja(d,p());
        agregaADesarrollo(v.ID()+".d ← "+du+"\n\n");
    }

    protected void cicloVAdy4(){
        cambiaPaso(nulo(8) ? 12 : 8, nulo(8) ? 13 : 9);
        if(p[v.nV()]!=null)
            marcaArista(v.nV(), p[v.nV()].nV(), "\""+color+"\"", false);
        p[v.nV()] = u;
        dibuja(d,p());
        agregaADesarrollo("El predecesor de  "+v.ID()+" es "+u.ID()+"\n\n");        
    }

    protected void cicloVAdy5(){
        cambiaPaso(9,10);
        C.add(v);
        agregaADesarrollo("Se ha agregado "+v.ID()+" a C\n\n");
        clics1 = mueve(0    );
    }

    protected void cicloC2(){
        cambiaPaso(nulo(11+add) ? 5 : 11+add,12+add);
        C.remove();
        agregaADesarrollo("Se ha sacado a "+u.ID()+"\n\n");
    }

    protected void resultados0(){
        cambiaPaso(13+add,15+add);
        agregaADesarrollo("Los vértices en G son:\n");

        for(int i = 0;i<G.numV;i++){
            agregaADesarrollo("-"+G.getV(i).ID()+"\n");
        }

        agregaADesarrollo("\n");
        clics++;
        clics0 = 0;
        clics1 = 0;
    }

    protected void resultadosI0(){
        if(nV<G.numV){
            cambiaPaso(nulo(15+add) ? 22+add : 15+add,17+add);
            agregaADesarrollo("La distancia a "+G.getV(nV).ID()+" es: "+(d[nV]!=Integer.MAX_VALUE ? d[nV] : "∞")+"\n");
            v = G.getV(nV);
            if(d[nV++]==Integer.MAX_VALUE)
              return;
            clics0++;
        }
        else{
            cambiaPaso(nulo(15+add) ? nulo(17+add) ? 22+add : 17+add : 15+add, 23+add);
            agregaADesarrollo("Fin del algoritmo");
            clics = 10;
        }
    }

    protected void resultadosI1(){
        cambiaPaso(17+add,19+add);
        clics0++;
        agregaADesarrollo("El camino a "+v.ID()+" es:\n");
    }

    protected void resultadosD0(){
        cambiaPaso(nulo(19+add) ? 21+add : 19+add ,20+add);
        agregaADesarrollo(v.ID()+(  p[v.nV()] != null ? "," : "\n"));
        clics1++;
    }

    protected void resultadosD1(){
        cambiaPaso(20+add,21+add);
        v = p[v.nV()];
        //enviaMensaje("v es ahora: "+(v!=null ? v.ID() : "nulo\n"));
        clics0 = v==null ? clics0+1 : clics0;
        clics1++;
    }

    protected void resultadosI2(){
        cambiaPaso(21+add,22+add);
        agregaADesarrollo("v es nulo\n");
        clics0++;
    }

    protected void resultados1(){
        cambiaPaso(22+add,23+add);
        agregaADesarrollo("Fin del algoritmo");
    }

     public void ejecutaPaso(){
        switch(clics){
            case 0:
                inicializa();
                break;
            case 1:
                inicializa1();
                break;
            case 2:
                inicializa2();
                break;
            case 3:
                switch(clics0%4){
                    case 0:
                        cicloC0();
                        break;
                    case 1:
                        cicloC1();
                        break;
                    case 2:
                        switch(clics1%7){
                            case 0:
                                cicloVAdy0();
                               break;
                            case 1:
                                cicloVAdy1();
                                break;
                            case 2:
                                cicloVAdy2();
                                break;
                           case 3:
                                cicloVAdy3();
                                break;
                           case 4:
                                cicloVAdy4();
                                break;
                           case 5:
                                cicloVAdy5();
                                break;
                            case 6:
                                adicionales();
                                break;
                        }
                        clics1++;
                        return;
                    case 3:
                        cicloC2();
                        break;
                }
                clics0++;
                return;
           case 4:
               resultados0();
                break;
           case 5:
                switch(clics0%4){
                    case 0:
                        resultadosI0();
                       break;
                    case 1:
                        resultadosI1();
                        break;
                    case 2:
                        switch(clics1%2){
                            case 0:
                                resultadosD0();
                               break;
                            case 1:
                                resultadosD1();
                               break;
                        }
                        break;
                   case 3:
                        resultadosI2();
                        break;
                }
                break;
          case 6:
             resultados1();
             break;
        }
    }

}
